//--------------------------------------------------------------------------------
// Copyright (c) 2012, Secular Wheel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//	- Redistributions of source code must retain the above copyright notice, 
//	  this list of conditions and the following disclaimer.
//	- Redistributions in binary form must reproduce the above copyright notice, this
//	  list of conditions and the following disclaimer in the documentation and/or other 
//	  materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//--------------------------------------------------------------------------------

#include "../include/jpx_dec.h"

jpx_bool					jpc_decode_codeblock_seg_arith(jpc_decp jpcdec, jpc_tilecompp tc, jpx_uint32 r, jpx_uint32 sb, jpc_codeblockp cb, jpc_segmentp seg,
														   jpx_int32p data, jpx_int32 wd, jpc_coeffstatep states, jpx_int32 ws);
jpx_bool					jpc_decode_codeblock_seg_raw(jpc_decp jpcdec, jpc_tilecompp tc, jpx_uint32 r, jpx_uint32 sb, jpc_codeblockp cb, jpc_segmentp seg,
														 jpx_int32p data, jpx_int32 wd, jpc_coeffstatep states, jpx_int32 ws);

const jpx_byte	g_sig_lx_map[512] = {	// Map significance propagation states to context label for LL/LH bands. 
	0x00,0x01,0x03,0x03,0x01,0x02,0x03,0x03,0x05,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x00,0x01,0x03,0x03,0x01,0x02,0x03,0x03,0x05,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x05,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x05,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x01,0x02,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x01,0x02,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x01,0x02,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x01,0x02,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x02,0x02,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x02,0x02,0x03,0x03,0x02,0x02,0x03,0x03,0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,
	0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x06,0x06,0x07,0x07,0x06,0x06,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x03,0x03,0x04,0x04,0x03,0x03,0x04,0x04,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
	0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
};
const jpx_byte	g_sig_hl_map[512] = {	// Map significance propagation states to context label for HL bands. 
	0x00,0x01,0x05,0x06,0x01,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x00,0x01,0x05,0x06,0x01,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x01,0x02,0x06,0x06,0x02,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x01,0x02,0x06,0x06,0x02,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x05,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x05,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x06,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x06,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x01,0x02,0x06,0x06,0x02,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x01,0x02,0x06,0x06,0x02,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x02,0x02,0x06,0x06,0x02,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x02,0x02,0x06,0x06,0x02,0x02,0x06,0x06,0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x03,0x03,0x07,0x07,0x03,0x03,0x07,0x07,0x04,0x04,0x07,0x07,0x04,0x04,0x07,0x07,
	0x06,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x06,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x06,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x06,0x06,0x08,0x08,0x06,0x06,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,
	0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08,0x07,0x07,0x08,0x08
};
const jpx_byte	g_sig_hh_map[512] = {	// Map significance propagation states to context label for HH bands. 
	0x00,0x03,0x01,0x04,0x03,0x06,0x04,0x07,0x01,0x04,0x02,0x05,0x04,0x07,0x05,0x07,
	0x00,0x03,0x01,0x04,0x03,0x06,0x04,0x07,0x01,0x04,0x02,0x05,0x04,0x07,0x05,0x07,
	0x01,0x04,0x02,0x05,0x04,0x07,0x05,0x07,0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,
	0x01,0x04,0x02,0x05,0x04,0x07,0x05,0x07,0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,
	0x03,0x06,0x04,0x07,0x06,0x08,0x07,0x08,0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x03,0x06,0x04,0x07,0x06,0x08,0x07,0x08,0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x01,0x04,0x02,0x05,0x04,0x07,0x05,0x07,0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,
	0x01,0x04,0x02,0x05,0x04,0x07,0x05,0x07,0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,
	0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,
	0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,0x02,0x05,0x02,0x05,0x05,0x07,0x05,0x07,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x03,0x06,0x04,0x07,0x06,0x08,0x07,0x08,0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x03,0x06,0x04,0x07,0x06,0x08,0x07,0x08,0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x06,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x06,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x04,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,0x05,0x07,0x05,0x07,0x07,0x08,0x07,0x08,
	0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,
	0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08,0x07,0x08,0x07,0x08,0x08,0x08,0x08,0x08
};

const jpx_byte	g_sgn_map[256] = {	// Map sign bit and xor-bit states to context label.
	0x12,0x12,0x18,0x19,0x12,0x12,0x18,0x19,0x18,0x18,0x18,0x12,0x19,0x19,0x12,0x19,
	0x12,0x12,0x18,0x19,0x12,0x12,0x18,0x19,0x18,0x18,0x18,0x12,0x19,0x19,0x12,0x19,
	0x14,0x14,0x1a,0x17,0x14,0x14,0x1a,0x17,0x1a,0x1a,0x1a,0x14,0x17,0x17,0x14,0x17,
	0x15,0x15,0x16,0x1b,0x15,0x15,0x16,0x1b,0x16,0x16,0x16,0x15,0x1b,0x1b,0x15,0x1b,
	0x12,0x12,0x18,0x19,0x12,0x12,0x18,0x19,0x18,0x18,0x18,0x12,0x19,0x19,0x12,0x19,
	0x12,0x12,0x18,0x19,0x12,0x12,0x18,0x19,0x18,0x18,0x18,0x12,0x19,0x19,0x12,0x19,
	0x14,0x14,0x1a,0x17,0x14,0x14,0x1a,0x17,0x1a,0x1a,0x1a,0x14,0x17,0x17,0x14,0x17,
	0x15,0x15,0x16,0x1b,0x15,0x15,0x16,0x1b,0x16,0x16,0x16,0x15,0x1b,0x1b,0x15,0x1b,
	0x14,0x14,0x1a,0x17,0x14,0x14,0x1a,0x17,0x1a,0x1a,0x1a,0x14,0x17,0x17,0x14,0x17,
	0x14,0x14,0x1a,0x17,0x14,0x14,0x1a,0x17,0x1a,0x1a,0x1a,0x14,0x17,0x17,0x14,0x17,
	0x14,0x14,0x1a,0x17,0x14,0x14,0x1a,0x17,0x1a,0x1a,0x1a,0x14,0x17,0x17,0x14,0x17,
	0x12,0x12,0x18,0x19,0x12,0x12,0x18,0x19,0x18,0x18,0x18,0x12,0x19,0x19,0x12,0x19,
	0x15,0x15,0x16,0x1b,0x15,0x15,0x16,0x1b,0x16,0x16,0x16,0x15,0x1b,0x1b,0x15,0x1b,
	0x15,0x15,0x16,0x1b,0x15,0x15,0x16,0x1b,0x16,0x16,0x16,0x15,0x1b,0x1b,0x15,0x1b,
	0x12,0x12,0x18,0x19,0x12,0x12,0x18,0x19,0x18,0x18,0x18,0x12,0x19,0x19,0x12,0x19,
	0x15,0x15,0x16,0x1b,0x15,0x15,0x16,0x1b,0x16,0x16,0x16,0x15,0x1b,0x1b,0x15,0x1b
};

jpx_bool				jpc_decode_codeblock(jpc_decp jpcdec, jpc_tilecompp tc, jpx_uint32 r, jpx_uint32 sb, jpc_codeblockp cb, jpx_int32p data, jpx_int32 wd)
{
	jpx_int32 ws;
	jpc_segmentp seg;
	jpc_coeffstatep states, state0, state;
	jpc_subbandp subband;
	jpx_int32 val, shift;
	jpx_uint32 x, y;
	jpx_byte nb;
	jpx_int32p ptr, ptr0;
	
	ws = cb->x1 - cb->x0 + 3;
	states = (jpc_coeffstatep)jpcdec->memmgr->alloc_func(jpcdec->memmgr, ws*(cb->y1-cb->y0+2)*sizeof(jpc_coeffstate));
	jpx_memset(states, 0, ws*(cb->y1-cb->y0+2)*sizeof(jpc_coeffstate));
	
	seg = cb->seglist->header;
	while (seg) {
		if (seg->type == JPC_SEGMENT_RAW) {
			if (!jpc_decode_codeblock_seg_raw(jpcdec, tc, r, sb, cb, seg, data, wd, states, ws)) {
				jpcdec->memmgr->free_func(jpcdec->memmgr, states);
				return jpx_false;
			}
		} else {
			if (!jpc_decode_codeblock_seg_arith(jpcdec, tc, r, sb, cb, seg, data, wd, states, ws)) {
				jpcdec->memmgr->free_func(jpcdec->memmgr, states);
				return jpx_false;
			}
		}
		seg = seg->next;
	}

	subband = &tc->reslevels[r].subbands[sb];
	ptr0 = data;
	state0 = states + 1 + ws;
	for (y = 0; y < cb->y1-cb->y0; y++, state0+=ws, ptr0+=wd) {
		for (x=0, state=state0, ptr=ptr0; x < cb->x1-cb->x0; x++, ptr++, state++) {
			val = *ptr;
			nb = state->len + cb->p;
			
			// Undo region of interest
			if (tc->roi_shift) {
				if (nb >= subband->mb) {
					if (val >> (nb-subband->mb)) {
						val >>= nb-subband->mb;
						nb = subband->mb;
					} else {
						nb = nb>tc->roi_shift ? (nb-tc->roi_shift):0;
					}
				}
			}
			
			// Do de-quantization.
			if (val != 0) {
				if ((tc->quantization_style&0x1f) != 0) {
					shift = subband->mb - nb;
					val = shift > 0 ? (val<<shift)|(1<<(shift-1)) : (val>>-shift);
					val = subband->shift > 0 ? (val<<subband->shift) : (val>>-subband->shift);
					val = JPX_FIXMUL(val,subband->delta);
				} else {
					shift = subband->mb - nb;
					val = shift > 0 ? (val<<shift)|(1<<(shift-1)) : (val>>-shift);
					val <<= 2;
				}
				if (state->sign) {
					val = -val;
				}
			}
			*ptr = val;

#ifdef _JPX_ENABLE_DEQUANT_LOG_
			JPX_LOG("%d\n", val);
#endif
		}
	}

	jpcdec->memmgr->free_func(jpcdec->memmgr, states);
	return jpx_true;
}
jpx_bool					jpc_decode_codeblock_seg_arith(jpc_decp jpcdec, jpc_tilecompp tc, jpx_uint32 r, jpx_uint32 sb, jpc_codeblockp cb, jpc_segmentp seg,
														   jpx_int32p data, jpx_int32 wd, jpc_coeffstatep states, jpx_int32 ws)
{
	jpx_streamp stream;
	jpx_bitstreamp bitstream;
	jpx_arith_decoderp arithdecoder;
	jpc_coeffstatep cs0, cs1, cs;
	jpx_int32p cd0, cd1, cd;
	jpx_uint32 x, y, state, i;
	jpx_int32 rows, k, uf, rows_used;
	jpx_uint16 tempwords[6], mask;
	jpx_uint16p line = &tempwords[1];
	jpx_const_bytep sig_cl_map;
	jpx_int32 cx, val;
	jpx_bool rl;
	
	if (r == 0) {
		sig_cl_map = g_sig_lx_map;
	} else {
		if (sb == 0) {
			sig_cl_map = g_sig_hl_map;
		} else if (sb == 1) {
			sig_cl_map = g_sig_lx_map;
		} else {
			sig_cl_map = g_sig_hh_map;
		}
	}
	
	stream = jpx_create_memstream(jpcdec->memmgr, seg->buf, seg->lentotal);
	bitstream = jpx_bitstream_create(jpcdec->memmgr, stream);
	arithdecoder = jpx_arith_decoder_create(jpcdec->memmgr, bitstream);
	
	mask = 0xffff - 2;
	for (i = 0; i < seg->passnum; i++) {
		switch (cb->passtype)
		{
		case JPC_SIG_PASS: {
				for (y=cb->y0, cs0=states+ws, cd0=data; y < cb->y1; y+=4, cs0+=ws<<2, cd0+=wd<<2) {
					if (y + 4 <= cb->y1) {
						rows = 4;
					} else {
						rows = cb->y1 - y;
					}
					
					rows_used = tc->code_block_style&JPC_CBSTYLE_CAUSAL ? rows : rows+1;
					line[rows] = 0;
					for (k = -1; k < rows_used; k++) {
						line[k] = (cs0[k*ws+1].significant<<1) | cs0[k*ws+2].significant;
					}
					
					for (x=cb->x0, cs1=cs0+1, cd1=cd0; x < cb->x1; x++, cs1++, cd1++) {
						for (k=0, cs=cs1, cd=cd1; k < rows; k++, cs+=ws, cd+=wd) {
							state = ((line[k-1]<<6) | (line[k]<<3) | line[k+1]) & 0x01ef;
							cx = sig_cl_map[state];
							if ((!cs->significant) && cx) {
								if (jpx_arith_decoder_decode(arithdecoder, &cb->contexts[cx], cx)) {
									*cd = (*cd<<1) | 1;
									cs->significant = 1;
									cs->refined = 0;
									state = (cs[-ws].significant<<7) | (cs[-ws].sign<<6);
									state |= (k+1<rows) || (rows!=rows_used) ? (cs[ws].significant<<5)|(cs[ws].sign<<4) : 0;
									state |= (cs[-1].significant<<3) | (cs[-1].sign<<2);
									state |= (cs[1].significant<<1) | cs[1].sign;
									cx = g_sgn_map[state] >> 1;
									cs->sign = jpx_arith_decoder_decode(arithdecoder, &cb->contexts[cx], cx) ^ (g_sgn_map[state] & 0x01);
								}
								cs->len ++;
								cs->handled = 1;
								
								line[k] = (line[k]&mask) | (cs->significant<<1);
							}
						}
						for (k=-1; k < rows_used; k++) {
							line[k] = ((line[k]<<1) | cs1[k*ws+2].significant) & 0x0007;
						}
					}
				}
			}
			cb->passtype = JPC_REF_PASS;
			break;
		case JPC_REF_PASS: {
				for (y=cb->y0, cs0=states+ws, cd0=data; y < cb->y1; y+=4, cs0+=ws<<2, cd0+=wd<<2) {
					if (y + 4 <= cb->y1) {
						rows = 4;
					} else {
						rows = cb->y1 - y;
					}
					
					rows_used = tc->code_block_style&JPC_CBSTYLE_CAUSAL ? rows : rows+1;
					line[rows] = 0;
					for (k = -1; k < rows_used; k++) {
						line[k] = (cs0[k*ws+1].significant<<1) | cs0[k*ws+2].significant;
					}
					
					for (x=cb->x0, cs1=cs0+1, cd1=cd0; x < cb->x1; x++, cs1++, cd1++) {
						for (k=0, cs=cs1, cd=cd1; k < rows; k++, cs+=ws, cd+=wd) {
							state = ((line[k-1]<<6) | (line[k]<<3) | line[k+1]) & 0x01ef;
							if (cs->significant && (!cs->handled)) {
								if (cs->refined) {
									cx = 16;
								} else {
									if (state) {
										cx = 15;
									} else { 
										cx = 14;
									}
								}
								*cd = (*cd<<1) | jpx_arith_decoder_decode(arithdecoder, &cb->contexts[cx], cx);
								
								cs->len ++;
								cs->handled = 1;
								cs->refined = 1;
								
								line[k] = (line[k]&mask) | (cs->significant<<1);
							}
						}
						for (k = -1; k < rows_used; k++) {
							line[k] = ((line[k]<<1) | cs1[k*ws+2].significant) & 0x0007;
						}
					}
				}
			}
			cb->passtype = JPC_CLN_PASS;
			break;
		case JPC_CLN_PASS: {
				for (y=cb->y0, cs0=states+ws, cd0=data; y < cb->y1; y+=4, cs0+=ws<<2, cd0+=wd<<2) {
					if (y + 4 <= cb->y1) {
						rows = 4;
					} else {
						rows = cb->y1 - y;
					}
					
					rows_used = tc->code_block_style&JPC_CBSTYLE_CAUSAL ? rows : rows+1;
					line[rows] = 0;
					for (k = -1; k < rows_used; k++) {
						line[k] = (cs0[k*ws+1].significant<<1) | cs0[k*ws+2].significant;
					}
					
					for (x=cb->x0, cs1=cs0+1, cd1=cd0; x < cb->x1; x++, cs1++, cd1++) {
						if (rows == 4) {
							rl = 1;
							for (k=0, cs=cs1; k < rows; k++, cs+=ws) {
								state = ((line[k-1]<<6) | (line[k]<<3) | line[k+1]) & 0x01ef;
								if ((sig_cl_map[state]!=0) || cs->handled || cs->significant) {
									rl = 0;
									break;
								}
							}
						} else {
							rl = 0;
						}
						
						k = 0;
						cs = cs1;
						cd = cd1;
						if (rl) {
							if (jpx_arith_decoder_decode(arithdecoder, &cb->contexts[17], 17)) {
								uf = jpx_arith_decoder_decode(arithdecoder, &cb->contexts[18], 18);
								uf = (uf << 1) | jpx_arith_decoder_decode(arithdecoder, &cb->contexts[18], 18);
								
								for ( ; k < uf; k++, cs+=ws, cd+=wd) {
									cs->len ++;
								}
								*cd = (*cd<<1) | 1;
								cs->len ++;
								cs->refined = 0;
								cs->significant = 1;
								state = (cs[-ws].significant<<7) | (cs[-ws].sign<<6);
								state |= (k+1<rows) || (rows!=rows_used) ? (cs[ws].significant<<5)|(cs[ws].sign<<4) : 0;
								state |= (cs[-1].significant<<3) | (cs[-1].sign<<2);
								state |= (cs[1].significant<<1) | cs[1].sign;
								cx = g_sgn_map[state] >> 1;
								cs[0].sign = jpx_arith_decoder_decode(arithdecoder, &cb->contexts[cx], cx) ^ (g_sgn_map[state]&0x01);
								
								line[k] = (line[k]&mask) | (cs->significant<<1);
								
								k++;
								cs += ws;
								cd += wd;
							} else {
								for ( ; k < rows; k++, cs+=ws, cd+=wd) {
									cs->len ++;
								}
							}
						}
						
						
						for ( ; k < rows; k++, cs+=ws, cd+=wd) {
							if (!cs->significant && !cs->handled) {
								state = ((line[k-1]<<6) | (line[k]<<3) | line[k+1]) & 0x01ef;
								cx = sig_cl_map[state];
								if (jpx_arith_decoder_decode(arithdecoder, &cb->contexts[cx], cx)) {
									*cd = (*cd<<1) | 1;
									cs->significant = 1;
									cs->refined = 0;
									state = (cs[-ws].significant<<7) | (cs[-ws].sign<<6);
									state |= (k+1<rows) || (rows!=rows_used) ? (cs[ws].significant<<5)|(cs[ws].sign << 4) : 0;
									state |= (cs[-1].significant<<3) | (cs[-1].sign<<2);
									state |= (cs[1].significant<<1) | cs[1].sign;
									cx = g_sgn_map[state] >> 1;
									cs[0].sign = jpx_arith_decoder_decode(arithdecoder, &cb->contexts[cx], cx) ^ (g_sgn_map[state] & 0x01);
									
									line[k] = (line[k]&mask) | (cs->significant<<1);
								}
								
								cs->len ++;
							}
							
						}
						for (k = -1; k < rows_used; k++) {
							line[k] = ((line[k]<<1) | cs1[k*ws+2].significant) & 0x0007;
						}
						for (k = 0, cs = cs1; k < rows; k++,cs += ws) {
							cs->handled = 0;
						}
					}
				}
				if (tc->code_block_style & JPC_CBSTYLE_SYMBOL) {
					val = 0;
					for (k = 0; k < 4; k++) {
						val = (val<<1) | jpx_arith_decoder_decode(arithdecoder, &cb->contexts[18], cx);
					}
					if (val != 0x0a) {
						if (jpcdec->error_func) {
							jpcdec->error_func("Error resilience segmentation symbol is not 0x0a.");
						}
						jpx_arith_decoder_destroy(jpcdec->memmgr, arithdecoder);
						jpx_bitstream_destroy(jpcdec->memmgr, bitstream);
						stream->destroy_func(stream);
						return jpx_false;
					}
				}
			}
			cb->passtype = JPC_SIG_PASS;
			break;
		}
		
		if (tc->code_block_style & JPC_CBSTYLE_RESET) {
			jpx_arith_reset_contexts(cb->contexts);
		}
	}
	jpx_arith_decoder_destroy(jpcdec->memmgr, arithdecoder);
	jpx_bitstream_destroy(jpcdec->memmgr, bitstream);
	stream->destroy_func(stream);
	return jpx_true;
}
jpx_bool					jpc_decode_codeblock_seg_raw(jpc_decp jpcdec, jpc_tilecompp tc, jpx_uint32 r, jpx_uint32 sb, jpc_codeblockp cb, jpc_segmentp seg,
														 jpx_int32p data, jpx_int32 wd, jpc_coeffstatep states, jpx_int32 ws)
{
	jpx_streamp	stream;
	jpx_bitstreamp bitstream;
	jpx_bitstuffp bitstuff;
	jpc_coeffstatep cs0, cs1, cs;
	jpx_int32p cd0, cd1, cd;
	jpx_uint32 x, y, state, i;
	jpx_int32 rows, k, rows_used;
	jpx_uint16 tempwords[6], mask; 
	jpx_uint16p line = &tempwords[1];
	
	stream = jpx_create_memstream(jpcdec->memmgr, seg->buf, seg->lentotal);
	bitstream = jpx_bitstream_create(jpcdec->memmgr, stream);
	bitstuff = jpx_bitstuff_create(jpcdec->memmgr, bitstream);
	
	mask = 0xffff - 2;
	for (i = 0; i < seg->passnum; i++) {
		switch (cb->passtype)
		{
		case JPC_SIG_PASS: {
				for (y=cb->y0, cs0=states+ws, cd0=data; y < cb->y1; y+=4, cs0+=ws<<2, cd0+=wd<<2) {
					if (y + 4 <= cb->y1) {
						rows = 4;
					} else {
						rows = cb->y1 - y;
					}
					
					rows_used = tc->code_block_style&JPC_CBSTYLE_CAUSAL ? rows : rows+1;
					line[rows] = 0;
					for (k = -1; k < rows_used; k++) {
						line[k] = (cs0[k*ws+1].significant<<1) | cs0[k*ws+2].significant;
					}
					
					for (x=cb->x0, cs1=cs0+1, cd1=cd0; x < cb->x1; x++, cs1++, cd1++) {
						for (k=0, cs=cs1, cd=cd1; k < rows; k++, cs+=ws, cd+=wd) {
							state = ((line[k-1]<<6) | (line[k]<<3) | line[k+1]) & 0x01ef;
							if (!cs->significant && state) {
								if (jpx_bitstuff_readbit(bitstuff)) {
									*cd = (*cd<<1) | 1;
									cs->significant = 1;
									cs->refined = 0;
									cs->sign = jpx_bitstuff_readbit(bitstuff);
								}
								cs->len ++;
								cs->handled = 1;
								
								line[k] = (line[k]&mask) | (cs->significant<<1);
							}
						}
						for (k = -1; k < rows_used; k++) {
							line[k] = ((line[k]<<1) | cs1[k*ws+2].significant) & 0x0007;
						}
					}
				}
			}
			cb->passtype = JPC_REF_PASS;
			break;
		case JPC_REF_PASS: {
				for (y=cb->y0, cs0=states+ws, cd0=data; y < cb->y1; y+=4, cs0+=ws<<2, cd0+=wd<<2) {
					if(y + 4 <= cb->y1) {
						rows = 4;
					} else {
						rows = cb->y1 - y;
					}
					
					for (x=cb->x0, cs1=cs0+1, cd1=cd0; x < cb->x1; x++, cs1++, cd1++) {
						for (k=0, cs=cs1, cd=cd1; k < rows; k++, cs+=ws, cd+=wd) {
							if (cs->significant && !cs->handled) {
								*cd = (*cd << 1) | jpx_bitstuff_readbit(bitstuff);
								
								cs->len ++;
								cs->handled = 1;
								cs->refined = 1;
							}
						}
					}
				}

				if (tc->code_block_style & JPC_CBSTYLE_PREDICT) {
					if (!jpx_bitstuff_checkpredict(bitstuff)) {
						if (jpcdec->error_func) {
							jpcdec->error_func("Code-block stream predictable termination check failed.");
						}
						jpx_bitstuff_destroy(jpcdec->memmgr, bitstuff);
						jpx_bitstream_destroy(jpcdec->memmgr, bitstream);
						stream->destroy_func(stream);
						return jpx_false;
					}
				}
			}
			cb->passtype = JPC_CLN_PASS;
			break;
		}
	}
	jpx_bitstuff_destroy(jpcdec->memmgr, bitstuff);
	jpx_bitstream_destroy(jpcdec->memmgr, bitstream);
	stream->destroy_func(stream);
	return jpx_true;
}
